<template>
  <div>
    <div id="container"></div>
  </div>
</template>

<script lang="ts" setup>
import * as data from '@/assets/data/antvX6.ts'

import { Graph, Cell } from '@antv/x6'
import ELK, { ElkNode, ElkEdge, ElkExtendedEdge } from 'elkjs'

import { onMounted } from 'vue'
onMounted(() => {

  const graph = new Graph({
    container: document.getElementById('container')!,
    interacting: false,
  })

  // 注册节点
  Graph.registerNode(
    'elk-node',
    {
      inherit: 'rect',
      attrs: {
        body: {
          fill: '#EFF4FF',
          stroke: '#5F95FF',
          strokeWidth: 1
        },
        label: {
          // refX: 0,
          // refY: 0,
          // textAnchor: 'start',
          // textVerticalAnchor: 'bottom',
          // fontSize: 11,
          // text: 'left',
          fill: '#888',
          fontSize: 12
        },
      },
      ports: {
        groups: {
          port: {
            position: {
              name: 'absolute',
              args: {
                compensateRotate: true,
              },
            },
            label: {
              position: {
                name: 'bottom',
              },
            },
            attrs: {
              portBody: {
                magnet: 'passive',
                fill: '#5F95FF',
                refWidth: '100%',
                refHeight: '100%'
              },
            },
            markup: [
              {
                tagName: 'rect',
                selector: 'portBody',
              },
            ],
          },
        },
      },
      label: {
        position: 'radial',
      },
    },
    true,
  )

  // 注册边
  Graph.registerEdge(
    'elk-edge',
    {
      inherit: 'edge',
      attrs: {
        line: {
          stroke: '#A2B1C3',
          strokeWidth: 1,
          targetMarker: {
            name: 'block',
            width: 1,
            height: 1,
          },
        },
      },
    },
    true,
  )

  interface Position {
    x: number
    y: number
  }

  const portIdToNodeIdMap: Record<string, string> = {}
  const cells: Cell[] = []

  // 添加孩子节点
  const addChildren = (children: ElkNode[], pos?: Position) => {
    children.forEach((child) => {
      const position = {
        x: (child.x || 0) + (pos ? pos.x : 0),
        y: (child.y || 0) + (pos ? pos.y : 0),
      }
      let label: string = ''
      if (typeof child.labels === 'string') {
        label = child.labels
      } else if (Array.isArray(child.labels) && child.labels[0]) {
        label = child.labels[0].text
      }
      const node = graph.createNode({
        shape: 'elk-node',
        id: child.id,
        position,
        label,
        size: {
          width: child.width || 0,
          height: child.height || 0,
        },
        ports: {
          items: (child.ports || []).map((item: any) => {
            portIdToNodeIdMap[item.id] = child.id
            return {
              id: item.id,
              group: 'port',
              args: {
                x: item.x,
                y: item.y,
              },
              size: {
                width: item.width || 0,
                height: item.height || 0,
              },
              attrs: {
                text: {
                  text: item.label || '', // 标签文本
                  fontSize: 10,
                  fill: 'green'
                },
              },
            }
          }),
        },
      })

      cells.push(node)

      if (child.children) {
        addChildren(child.children, position)
      }

      if (child.edges) {
        addEdges(child.edges, position)
      }
    })
  }

  // 添加边
  const addEdges = (edges: ElkEdge[], pos?: Position) => {
    edges.forEach((edge: ElkExtendedEdge) => {
      const { bendPoints = [] } = edge.sections[0]

      if (pos) {
        bendPoints.map((bendPoint: Position) => {
          bendPoint.x += pos.x
          bendPoint.y += pos.y
        })
      }

      const sourcePortId = edge.sources[0]
      const targetPortId = edge.targets[0]
      const sourceNodeId = portIdToNodeIdMap[sourcePortId]
      const targetNodeId = portIdToNodeIdMap[targetPortId]

      cells.push(
        graph.createEdge({
          shape: 'elk-edge',
          source: {
            cell: sourceNodeId,
            port: sourcePortId,
          },
          target: {
            cell: targetNodeId,
            port: targetPortId,
          },
          vertices: bendPoints,
        }),
      )
    })
  }

  // 创建elk
  const elk = new ELK()

  elk.layout(data.jsonData).then((res: any) => {
    addChildren(res.children || [])
    addEdges(res.edges || [])
    graph.resetCells(cells)
    graph.zoomToFit({
      padding: 20,
      maxScale: 1,
    })
  })
})

</script>

<style lang="scss" scoped>
#container {
  width: 100%;
  height: 800px;
}
</style>